import sys, math, random
import neon.db_backend
import neon.verset

def permute(l):
    for i in xrange(1000):
        a = int(random.uniform(0, len(l)))
        b = int(random.uniform(0, len(l)))
        t = l[a]
        l[a] = l[b]
        l[b] = t
    return l

def check_is_set(vs, l, v = None):
    for i in xrange(len(l)):
        # print 'checking %s,%s' % l[i]
        d = vs.get_ver(l[i][0], l[i][1])
        if v is None:
            assert not (d is None)
        else:
            assert d == v[i]

def test_set(ids, vers, f):
    vs_factory.init_db(True)
    set_vers = []
    for id in ids:
        for i in f(vers):
            # print 'set %s,%s' % (id, i)
            vs.set_ver(id, i, 1)
            DB.commit()
            set_vers.append((id,i))
            check_is_set(vs, set_vers)


def dump_vers():
    print 'DB dump:'
    r = DB.exec_sql('select * from %s' % neon.verset.TABLE_NAME)
    if r is None:
        print '<empty>'
        return
    for i in r:
        print i

#------------------------------------------------------------------------------
import logging
import sys
# logging.basicConfig(level = logging.DEBUG)

if '--mysql' in sys.argv:
    DB = neon.db_backend.MySQL('localhost', 'neon', '', 'neon_test', True)
else:
    DB = neon.db_backend.Sqlite(':memory:', True)

DB.exec_sql('DROP TABLE IF EXISTS neon_mcast_ver;')

vs_factory = neon.verset.VerSetFactory(DB)
vs_factory.init_db(True)

MAX = 100
all_vers = range(MAX)
all_ids = ['id1', 'id2', 'id3']

vs = vs_factory.peer_set('id1')
for i in xrange(MAX):
    for j in all_ids:
        assert vs.get_ver(j, i) is None

# XXX/bowei -- handwritten sequences

# in order insertion
# try:
#     test_set(all_ids, all_vers, lambda x : x)
# except AssertionError, e:
#     print 'AssertionError ' + str(e)
#     dump_vers()
#     raise
    
# # random order
# try:
#     test_set(all_ids, all_vers, permute)
# except AssertionError, e:
#     print 'AssertionError ' + str(e)
#     dump_vers()
#     raise

try:
    # test diff iterator
    vs_factory.init_db(True)

    vs1_vers = {}
    vs2_vers = {}

    vs1_vers['id1'] = [1,4,5,6,10,11,12,15,16,20] 
    vs1_vers['id2'] = [10,9,8,2,5,15]     

    vs2_vers['id1'] = [1,5,6,10,12,15]
    vs2_vers['id2'] = [10,9,5]
    vs2_vers['id3'] = range(10) 

    def set_vs(vs, vers, vd = None):
        for id in vers:
            for v in vers[id]:
                vs.set_ver(id, v, 1)
                if vd:
                    vd.update((id, v))

    vs_1 = vs_factory.peer_set('id1')
    set_vs(vs_1, vs1_vers)
        
    vs_2 = vs_factory.peer_set('id2')
    set_vs(vs_2, vs2_vers)

    vd = neon.verset.VerSetDiff_Iter(vs_1, vs_2)
    
    def diff(vs1, vs2):
        diff = []
        for id in vs1:
            for v in vs1[id]:
                if v not in vs2[id]:
                    diff.append((id, v))
        return diff

    d = diff(vs1_vers, vs2_vers)
    for pv, _ in vd:
        d.remove(pv)
        vs_2.set_ver(pv[0], pv[1], 1)
    assert len(d) == 0

    vs2_vers['id1'] = list(set(vs2_vers['id1'] + vs1_vers['id1']))
    vs2_vers['id2'] = list(set(vs2_vers['id2'] + vs1_vers['id2']))

    new_vers = {'id1' : [2,3,7,9,13],
                'id2' : [1,4,5],
                'id3' : [1,2,4]}
    set_vs(vs_1, new_vers, vd)
    
    vs1_vers['id1'].extend(new_vers['id1'])
    vs1_vers['id2'].extend(new_vers['id2'])

    d = diff(vs1_vers, vs2_vers)
    for v in vd:
        d.remove(v[0])
    assert len(d) == 0

    set_vs(vs_1, {'id4': [1,2,99,5]}, vd)
    assert [pv for pv, _ in vd] == [('id4', 1), ('id4', 2), ('id4', 5), ('id4', 99)]

except AssertionError, e:
    print 'AssertionError ' + str(e)
    dump_vers()
    raise

# XXX/bowei -- split interval (different data annotations)
